//!  hirun-macros提供hirun的过程宏实现部分的功能
//!

#[allow(unused_extern_crates)]
extern crate proc_macro;

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{quote, ToTokens};
use syn::{parse_macro_input, ItemFn};

///
/// 如下的实现的async函数内部使用了Rc，因为不支持Send，无法利用tokio::spawn调度
///
/// ```rust
/// async fn foo() -> i32 {
///     let id = Rc::new(0);
///     bar(*id).await;
/// }
/// ```
/// 如下定义即可保证Rc可在Future内部正常使用，同时保证安全和性能
/// ```rust
/// #[hirun::future]
/// async fn foo() -> i32 {
///     let id = Rc::new(0);
///     bar(*id).await;
/// }
/// ```
///

#[proc_macro_attribute]
pub fn future(_args: TokenStream, item: TokenStream) -> TokenStream {
    let mut input = parse_macro_input!(item as ItemFn);

    if input.sig.asyncness.is_none() {
        let msg = "only used with `async` function";
        return syn::Error::new(Span::call_site(), msg)
            .into_compile_error()
            .into();
    }

    make_send_future(&mut input)
}

fn make_send_future(input: &mut ItemFn) -> TokenStream {
    let body = input.block.to_token_stream();

    let body_tokens: TokenStream = quote!({
    let future = unsafe { ::hirun::runtime::SendFuture::new(async move { #body }) };
    future.await
    })
    .into();

    let wrapper = parse_macro_input!(body_tokens as syn::Stmt);
    input.block.stmts.clear();
    input.block.stmts.push(wrapper);

    input.to_token_stream().into()
}

